﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using BTM_Client_Application.RealTimeFilter;
using BTM_Client_Application.SupportClasses;
using Client_Server_Interface;

namespace BTM_Client_Application
{
    /// <summary>
    /// Логика взаимодействия для ErrorList.xaml
    /// </summary>
    public partial class ErrorList
    {
        public delegate void ErrorDelegate(ErrorListRecordImpl newError);

        public event ErrorDelegate NewErrorEvent;

        protected virtual void OnNewErrorEvent(ErrorListRecordImpl newerror)
        {
            ErrorDelegate handler = NewErrorEvent;
            if (handler != null) handler(newerror);
        }

        public event ErrorDelegate RemovedErrorEvent;

        protected virtual void OnRemovedErrorEvent(ErrorListRecordImpl newerror)
        {
            ErrorDelegate handler = RemovedErrorEvent;
            if (handler != null) handler(newerror);
        }

        //private static ObservableCollection<ErrorListRecord> _errorRecords;
        //private static ObservableCollection<DataGridRow> _errorRows;
        private static ObservableCollection<ErrorListRecordImpl> _errorList;

        //private RealTimeFilterControl _filter;
        private DataGridAutoInitFilter<ErrorListRecordImpl> _filter;

        public int RecordsCount { get { return DataList.Items.Count; } }
        
        public ErrorList()
        {
            InitializeComponent();

            var egc1 = new DataGridTextColumn
            {
                //Header = Res.Rm.GetString("Region"),
                Header = "Region",
                Width = 150,
                Binding = new Binding("Region")
            };
            var egc2 = new DataGridTextColumn
            {
                //Header = Res.Rm.GetString("Station"),
                Header = "Station",
                Width = 110,
                Binding = new Binding("Station")
            };
            var egc3 = new DataGridTextColumn
            {
                //Header = Res.Rm.GetString("Source"),
                Header = "Device",
                Width = 140,
                Binding = new Binding("Device")
            };
            var egc4 = new DataGridTextColumn
            {
                //Header = Res.Rm.GetString("Source"),
                Header = "Status",
                Width = 140,
                Binding = new Binding("Status")
            };
            var egc5 = new DataGridTextColumn
            {
                //Header = Res.Rm.GetString("Info"),
                Header = "Info",
                Width = 140,
                Binding = new Binding("Info")
            };
            var egc6 = new DataGridTextColumn
                {
                //Header = Res.Rm.GetString("Date"),
                Header = "Date",
                Width = 140,
                Binding = new Binding("Date")
            };
            /*
            DataList.Columns.Add(egc1);
            DataList.Columns.Add(egc2);
            DataList.Columns.Add(egc3);
            DataList.Columns.Add(egc4);
            DataList.Columns.Add(egc5);
            DataList.Columns.Add(egc6);
            */
            //var dgrList = new List<DataGridRow>();
            
            //if(_errorRecords == null)
            //    _errorRecords = new ObservableCollection<ErrorListRecord>();
            //_errorRows = new ObservableCollection<DataGridRow>();
            _errorList = new ObservableCollection<ErrorListRecordImpl>();
            
            //_errorRecords.CollectionChanged += (sender, args) =>
            //    {
            //        foreach (var record in _errorRecords)
            //        {
            //            _errorRows.Add(new DataGridRow {Item = record, Background = new SolidColorBrush(Colors.Chartreuse)});
            //        }
            //    };
            //DataList.ItemsSource = _errorRecords;
            

            Initialize();
            
        }

        private void Initialize()
        {
            ErrorListRecordImpl.AvailableDevices = new List<object>(AliveInfo.MegaDeviceTree.Devices.Count);

            foreach (var device in AliveInfo.MegaDeviceTree.Devices.OrderBy(x=>x.DevInfo.Title))
            {
                ErrorListRecordImpl.AvailableDevices.Add(device.DevInfo.Title);
            }

            ErrorListRecordImpl.AvailableStations = new List<object>(AliveInfo.MegaDeviceTree.Stations.Count);
            
            foreach (var station in AliveInfo.MegaDeviceTree.Stations.OrderBy(x => x.Info.Station))
            {
                ErrorListRecordImpl.AvailableStations.Add(station.Info.Station);
            }

            ErrorListRecordImpl.AvailableRegions = new List<object>(AliveInfo.MegaDeviceTree.Regions.Count);

            foreach (var region in AliveInfo.MegaDeviceTree.Regions.OrderBy(x=>x.ToString(CultureInfo.InvariantCulture)))
            {
                ErrorListRecordImpl.AvailableRegions.Add(region);
            }

            //Инициализируем фильтр
            List<DataGridColumn> dgcList;
            _filter = new DataGridAutoInitFilter<ErrorListRecordImpl>(new ErrorListRecordImpl(), ref _errorList,
                                                                      out dgcList);
            foreach (var column in dgcList)
            {
                DataList.Columns.Add(column);
            }
            _filter.FilterControl.VerticalAlignment = VerticalAlignment.Stretch;
            _filter.FilterControl.HorizontalAlignment = HorizontalAlignment.Stretch;

            //_errorRows.ItemSource = _filter.FilteredItems;
            //DataList.ItemsSource = _errorRows;
            DataList.ItemsSource = _filter.FilteredItems;
            //DataList.Items.SortDescriptions.Add(new SortDescription("Date", ListSortDirection.Descending));

            FilterContainer.Children.Add(_filter.FilterControl);
            NewErrorEvent += _filter.On_NewError;
            RemovedErrorEvent += _filter.On_RemoveError;
        }

        public UIElement GetControl(out VoidDelegate del)
        {
            del = () =>
            { };
            //_newLogEntriesAmount = 0;
            return this;
        }

        public void Clear()
        {
            //_errorRows.Clear();
            //_errorRecords.Clear();
        }

        public void UpdateErrorRecords(ObservableCollection<ErrorListRecord> errorList)
        {
            foreach (var record in errorList)
            {
                switch (record.State)
                {
                    case ErrorListRecord.RecordState.Add:
                        //_errorRecords.Add(record);
                        //Color color;
                        
                        NewError(record);
                        break;
                    case ErrorListRecord.RecordState.Delete:
                        RemoveError(record);
                        //var it = _errorRows.Single(x => Equals(x.Item, record));
                        //_errorRows.Remove(it);

                        //_errorRecords.Remove(record);
                        break;
                }
            }
        }
        private void NewError(ErrorListRecord error)
        {
            //_errorRows.Add(new DataGridRow { Item = error });
            var ne = new ErrorListRecordImpl(error);
            switch (error.Status)
            {
                
                case "err":
                    ne.Status = ErrorStatus.CRITICAL;
                    ne.ItemBackground = Res.StatusColor.Critical;
                    break;
                case ErrorStatus.CRITICAL:
                    ne.ItemBackground = Res.StatusColor.Critical;
                    break;
                case ErrorStatus.ALARM:
                    ne.ItemBackground = Res.StatusColor.Alarm;
                    break;
                case ErrorStatus.WARNING:
                    ne.ItemBackground = Res.StatusColor.Warning;
                    break;
                case ErrorStatus.MINOR:
                    ne.ItemBackground = Res.StatusColor.Minor;
                    break;
                default:
                    ne.ItemBackground = new SolidColorBrush(Colors.Transparent);
                    break;
            }
            _errorList.Add(ne);
            SoundsWorker.NewErrorPlay();
            OnNewErrorEvent(ne);
        }

        private void RemoveError(ErrorListRecord error)
        {
            /*var ier = _errorRows.Single(x => Equals(x.Item, error));
            _errorRows.Remove(ier);*/
            var re = new ErrorListRecordImpl(error);
            var iel = _errorList.Single(x => x.GetRecordId() == error.GetRecordId());
            _errorList.Remove(iel);
            OnRemovedErrorEvent(re);
        }

        public void UiLanguageChanged()
        {
            DataList.Columns[0].Header = Res.Rm.GetString("Region", AliveInfo.CurrentCulture);
        }
        
        public class ErrorListRecordImpl : ErrorListRecord, IRealTimeFilterObject
        {
            
            private readonly Dictionary<string, object> _filterElements;

            //DataGrid Column Titles
            private static readonly string RegionTitle = Res.Rm.GetString("Region", AliveInfo.CurrentCulture);
            private static readonly string StationTitle = Res.Rm.GetString("Station", AliveInfo.CurrentCulture);
            private static readonly string DeviceTitle = Res.Rm.GetString("Device", AliveInfo.CurrentCulture);
            private static readonly string StatusTitle = Res.Rm.GetString("Status", AliveInfo.CurrentCulture);
            private static readonly string InfoTitle = Res.Rm.GetString("Info", AliveInfo.CurrentCulture);
            private static readonly string DateTitle = Res.Rm.GetString("Time", AliveInfo.CurrentCulture);

            private static Dictionary<string, FilterElementInitializer> _filterInterface;

            //Contains available items for specific properties. Use public properties when creating filter elements
            private static List<object> _avRegions;     //List of available regions
            private static List<object> _avStations;    //List of available stations
            private static List<object> _avDevices;     //List of available devices

            //List of available regions.
            public static List<object> AvailableRegions
            {
                get { return _avRegions; }
                set
                {
                    _avRegions = value;
                    _filterInterface[RegionTitle].ElementVariants = value;
                }
            }

            //List of available stations.
            public static List<object> AvailableStations
            {
                get { return _avStations; }
                set
                {
                    _avStations = value;
                    _filterInterface[StationTitle].ElementVariants = value;
                }
            }

            //List of available devices.
            public static List<object> AvailableDevices
            {
                get { return _avDevices; }
                set
                {
                    _avDevices = value;
                    _filterInterface[DeviceTitle].ElementVariants = value;
                }
            }

            /// <summary>
            /// Used by filter when creating filter elements. Contains information about filter element type,
            /// column header, available items and name for DataGridColumnBinding.
            /// </summary>
            public Dictionary<string, FilterElementInitializer> FilterInterface
            {
                get { return _filterInterface; }
            }

            /// <summary>
            /// Contains all members (region, station, ...) associated with name of filter. Used by the "Check" function of associated filter.
            /// </summary>
            public Dictionary<string, object> FilterElements
            {
                get
                {
                    if (_filterElements != null)
                        return _filterElements;
                    var d = new Dictionary<string, object>(6)
                        {
                            {RegionTitle, Region},
                            {StationTitle, Station},
                            {DeviceTitle, Device},
                            {StatusTitle, Status},
                            {InfoTitle, Info},
                            {DateTitle, Date}
                        };
                    return d;
                }
            }

            static ErrorListRecordImpl()
            {
                //Implementation of interface for creating filter elements
                _filterInterface = new Dictionary<string, FilterElementInitializer>(6)
                    {
                        {
                            //Filter element name
                            RegionTitle,
                            new FilterElementInitializer(elementType:FilterElementType.StringListContains, elementsVariant:null, columnInitializer:new DataGridColumnInitializer(RegionTitle, "Region"))
                        },
                        {
                            StationTitle,
                            new FilterElementInitializer(FilterElementType.StringListContains, null, new DataGridColumnInitializer(StationTitle, "Station"))
                        },
                        {
                            DeviceTitle,
                            new FilterElementInitializer(FilterElementType.StringListContains, null, new DataGridColumnInitializer(DeviceTitle, "Device"))
                        },
                        {StatusTitle, new FilterElementInitializer(FilterElementType.StringContains, null, new DataGridColumnInitializer(StatusTitle, "Status"))},
                        {InfoTitle, new FilterElementInitializer(FilterElementType.StringContains, null, new DataGridColumnInitializer(InfoTitle, "Info"))},
                        {DateTitle, new FilterElementInitializer(FilterElementType.StartAndEndTime, null, new DataGridColumnInitializer(DateTitle, "Date"))}
                        
                    };
            }

            /// <summary>
            /// BackGround of DataGridRow for item.
            /// </summary>
            public Brush ItemBackground { get; set; }
            
            public ErrorListRecordImpl()
            {
                ItemBackground = new SolidColorBrush(Colors.Transparent);
            }

            public ErrorListRecordImpl(ErrorListRecord record) : this()
            {
                
                Region = record.Region;
                Station = record.Station;
                Device = record.Device;
                Status = record.Status;
                Info = record.Info;
                Date = record.Date;
                _filterElements = new Dictionary<string, object>(6)
                    {
                        {RegionTitle, Region},
                        {StationTitle, Station},
                        {DeviceTitle, Device},
                        {StatusTitle, Status},
                        {InfoTitle, Info},
                        //{DateTitle, Date.ToString()}
                        {DateTitle, Date}
                    };
            }

            public ErrorListRecordImpl(ErrorListRecord record, List<object> avRegions, List<object> avStations, List<object> avDevices) :this(record)
            {
                AvailableRegions = avRegions;
                AvailableStations = avStations;
                AvailableDevices = avDevices;
            }
        }
        
    }
}
